---
title: Router context
description: Learn how to use the router context in your app.
---

## Built-in context

The router context is a shared object that is available to all procedures.

It contains the following properties:

- `ctx.session` - The current session, if available.
- `ctx.db` - The Drizzle database instance.
- `ctx.adapters` - Adapters for interacting with external services.
- `ctx.logger` - A logger instance.

### Session

The session object contains information about the current user.
It's signature depends on the used authentication provider and extends this base interface.

```ts
export interface Session {
  user: {
    id: string
    email?: string
    name?: string
  }
}
```

### Database

The Drizzle instance is available on `ctx.db` and can be used to interact with the database.

<Info>
  It's recommended to use services to interact with the database and keep the
  API layer thin.
</Info>

### Adapters

Adapters are used to interact with external services in a standardized way.

`ctx.adapters.billing` - The billing adapter, currently only `Stripe` is supported.

### Logger

The logger instance is available on `ctx.logger` and can be used to log messages.

This wraps `console.log` by default, but you can drop in your own logger, like `pino`.

```ts
// Log a message
ctx.logger.info('Hello world')

// Error, will be shown in the console
ctx.logger.error('Something went wrong')

// Debug, only shown when `debug` is enabled
ctx.logger.debug('Hello world')
```

## Extending the context

You can extend the context by adding your own properties in the `createTRPCContext` helper function.

Edit `packages/api/trpc/context.ts` and add your own properties:

```ts
//...
export const createTRPCContext = async <
  TSession extends Session = Session,
  Adapters extends ApiAdapters = ApiAdapters,
>(opts: {
  headers: Headers
  session: TSession | null
  adapters: Adapters
  debug?: boolean
}) => {
  const { session, adapters, debug } = opts

  const logger = {
    info: console.log,
    error: console.error,
    debug: (...args: any[]) => {
      if (debug) {
        console.log(...args)
      }
    },
  }

  if (debug) {
    const source = opts.headers.get('x-trpc-source') ?? 'unknown'
    console.log('>>> tRPC Request from', source, 'by', session?.user)
  }

  return {
    session,
    db,
    adapters,
    logger,
    // Add your own properties here
    myCustomProperty: 'Hello world',
  }
}
```

You can now access `ctx.myCustomProperty` in your procedures. Types are automatically inferred.

```ts
//...
  publicProcedure.mutation(async ({ ctx, input }) => {
    console.log(ctx.myCustomProperty)
  }),
```
